package controller;

import eccezioni.AnnuncioChiusoException;
import eccezioni.CampoErratoException;
import entity.Adesione;
import entity.Annuncio;
import entity.Articolo;
import entity.UtenteRegistrato;
import java.util.GregorianCalendar;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import sbForEntityClasses.AdesioneFacadeLocal;
import sbForEntityClasses.AnnuncioFacadeLocal;
import sbForEntityClasses.ArticoloFacadeLocal;
import sbForEntityClasses.UtenteRegistratoFacadeLocal;
import utilities.QueryBuilder;
import utilities.Regexp;

/**
 * Metodi per l'iscritto all'annuncio
 * @author Ale
 */
@Stateless
public class ControllerIscrizioneAnnuncio implements ControllerIscrizioneAnnuncioLocal {

    @EJB
    private ControllerAnnunciLocal controllerAnnunci;
    @EJB
    private UtenteRegistratoFacadeLocal utenteRegistratoFacade;
    @EJB
    private AnnuncioFacadeLocal annuncioFacade;
    @EJB
    private ArticoloFacadeLocal articoloFacade;
    @PersistenceContext(unitName = "ShippingShareBisBis-ejbPU")
    private EntityManager em;
    @EJB
    private AdesioneFacadeLocal adesioneFacade;

    /**
     * Salva nel database l'adesione temporanea in input
     * @param ad adesione temporanea da salvare
     */
    @Override
    public void salvaAdesioneTemporanea(Adesione ad) {
        for (Articolo art : ad.getArticoli()) {
            if (art.getId() == null) //non è ancora stato salvato sul database
            {
                articoloFacade.create(art);
            }
        }
        if (ad.getId() != null) { //è già nel database
            //l'utente è già iscritto a questo annuncio:
            //bisogna modificare l'adesione esistente
            adesioneFacade.edit(ad);
        } else {
            //l'utente si sta iscrivendo per la prima volta: faccio il persist dell'adesione in input
            adesioneFacade.create(ad);
            ad.getIscritto().getAdesioni().add(ad);
            utenteRegistratoFacade.edit(ad.getIscritto());
            ad.getAnnuncio().getAdesioni().add(ad);
            annuncioFacade.edit(ad.getAnnuncio());
        }
    }

    /**
     * Disiscrive un utente da un annuncio non ancora chiuso a cui aveva aderito
     * @param ad l'adesione di un utente a un annuncio
     * @throws AnnuncioChiusoException se l'annuncio a cui l'adesione si riferisce è già chiuso
     */
    @Override
    public void disiscriviDaAnnuncio(Adesione ad) throws AnnuncioChiusoException {
        UtenteRegistrato iscritto = ad.getIscritto();
        Annuncio a = ad.getAnnuncio();

        if (a.isChiuso()) {
            throw new AnnuncioChiusoException("Impossibile disiscriversi da un annuncio chiuso.");
        }

        iscritto.getAdesioni().remove(ad);
        utenteRegistratoFacade.edit(iscritto);

        a.getAdesioni().remove(ad);
        annuncioFacade.edit(a);

        for (Articolo art : ad.getArticoli()) {
            articoloFacade.remove(art);
        }

        ad.getArticoli().clear();

        adesioneFacade.remove(ad);
    }

    /**
     * Crea un articolo ma senza salvarlo nel database
     * @param urlArticolo url a cui si può acquistare l'articolo
     * @param prezzoStr prezzo dell'articolo
     * @param note eventuali note sull'articolo
     * @return il nuovo articolo
     * @throws CampoErratoException se uno o più dati forniti hanno un formato errato
     */
    @Override
    public Articolo creaArticolo(String urlArticolo, String prezzoStr, String note) throws CampoErratoException {
        if (note.equals("Scrivi qui eventuali note aggiuntive")) {
            note = "";
        }

        String errore = "";
        if (!Regexp.checkMoney(prezzoStr, true)) {
            errore += "<li>" + prezzoStr + " non &egrave; un prezzo corretto</li>";
        }
        if (!Regexp.checkURL(urlArticolo, true)) {
            errore += "<li>" + urlArticolo + " non &egrave; un indirizzo valido</li>";
        }
        if (!"".equals(errore)) {
            throw new CampoErratoException(errore);
        }

        float prezzo = Float.parseFloat(prezzoStr);

        Articolo art = new Articolo();
        art.setUrl(urlArticolo);
        art.setPrezzo(prezzo);
        art.setDescrizione(note);
        art.setStato(Articolo.Stato.IN_SOSPESO);

        return art;
    }

    /**
     * Salva il pagamento relativo a un'adesione
     * @param idAdesione l'adesione pagata
     */
    @Override
    public void salvaPagamento(long idAdesione) {
        Adesione adesione = controllerAnnunci.getAdesione(idAdesione);
        adesione.setPagata(true);
        adesioneFacade.edit(adesione);
    }

    /**
     * Verifica se l'utente in input ha già un'adesione o più ancora aperta per lo stesso sito
     * @param utenteLoggato l'utente la cui adesioen va verificata
     * @param sito il sito da cercare tra le adesioni dell'utente
     * @return la lista di adesioni dell'utente ancora aperte per lo stesso sito
     */
    @Override
    public List<Adesione> checkIscrittoSito(UtenteRegistrato utenteLoggato, String sito) {
        QueryBuilder qb = new QueryBuilder("Adesione", em);

        qb.addWhereEqClause("annuncio.sito.url", sito);
        qb.addWhereLessClause("annuncio.dataChiusura", new GregorianCalendar());
        qb.addWhereEqNumClause("iscritto.id", utenteLoggato.getId());

        Query q = qb.getQueryObject();
        return q.getResultList();
    }

    /**
     * Persistenza
     * @param object
     */
    public void persist(Object object) {
        em.persist(object);
    }
    
}
